# -*- Mode: Python; coding: utf-8; indent-tabs-mode: nil; tab-width: 4 -*-
### BEGIN LICENSE
# Copyright (C) YYYY Alexandros Fotiadis fotiadis90@gmail.com
# This program is free software: you can redistribute it and/or modify it 
# under the terms of the GNU General Public License version 3, as published 
# by the Free Software Foundation.
# 
# This program is distributed in the hope that it will be useful, but 
# WITHOUT ANY WARRANTY; without even the implied warranties of 
# MERCHANTABILITY, SATISFACTORY QUALITY, or FITNESS FOR A PARTICULAR 
# PURPOSE.  See the GNU General Public License for more details.
# 
# You should have received a copy of the GNU General Public License along 
# with this program.  If not, see <http://www.gnu.org/licenses/>.
### END LICENSE

from gettext import gettext as _
depend = ['android-tools-adb']
config = {}
CurrentGO = {}
PressedKeys = {}
MultiProcess = False
LastDeviceStatus = None
NewDeviceStatus = None
ID = ''
seqConfirmed = []
FinishtLoad = False
StatusChanges = False 
#Array from Combo list
CurrentCombo = {999: True}


def CheckDepends(win):
    #Logger Import
    from android_keyboard_lib.xlikan_lib import log
    logger = log()

    from android_keyboard_lib.xlikan_lib import InstallCheck

    win.StatusLab.set_text(_("Check Dependencies") + " ...")
    for app in depend:
        if(InstallCheck(app) is False):
            import sys
            logger.warning(_('Depend Application') + " " + app + " " + _('not Found'))
            sys.exit()
        else:
            logger.debug(_('Depend Application') + " " + app + " " + _('Found'))

    return True

def CheckADB(win):
    from android_keyboard_lib.xlikan_lib import log,findThisProcess; logger = log()
    import sys,os
    #Process Check
    if(findThisProcess('adb') == False):
        win.StatusLab.set_text(_("Starting ADB Deamon")+" ...")
        logger.debug(_('Start ADB')+' ...')
        os.system('adb start-server &> /dev/null && sleep 2')

        #Again Check
        if(findThisProcess('adb') == False):
            logger.error(_('Start ADB Failed'))
            sys.exit()
        else:
            return True
    else:
        return True

def readDevices(win):
    import os
    from android_keyboard_lib.xlikan_lib import log; logger = log()
    logger.debug(_("Start Read Devices ..."))

	NewCombo = {}
 	global CurrentCombo
	global config
	global FinishtLoad
	global StatusChanges
    FinishtLoad = False
	GLOBAL = {}
    Found = False
    DevCount = 0
	
    #Read Devices List
    output = os.popen('adb devices').read()
    Lines = output.split('\n')
    del Lines[0] #Remove Title

    NewCombo[0] = None #This value is Current if no Device Founded

    for device in Lines:
        if(device == ''):continue

        sets = device.split('\t')
        #DEVICE ID
        deviceID = sets[0]
        #DEVICE STATUS
		if(sets[1] == 'device'):sets[1] = 'Online'
		#STATUS
		deviceStatus = sets[1]
		
		
        logger.debug(_("Check Device")+" : "+deviceID+" ...")
        #Connection Check
        if(CheckDevice(deviceID) == False):
            continue

        Found = True #set founded devices True

        #Read Model Name

        deviceModel = getDeviceModel(deviceID)

        #Add to ComboBox
        NewCombo[DevCount] = deviceModel+'('+deviceStatus+')'

        logger.debug(_('Load Device')+' : '+deviceModel+'  '+_('Status')+' : '+deviceStatus)

        #ADD to GLOBAL
        GLOBAL[DevCount] = [deviceID, deviceModel, deviceStatus]
        DevCount+= 1


    if(CheckDeviceComboChanges(NewCombo) == False):
		FinishtLoad = True
		StatusChanges = False
		return
	else:
		StatusChanges = True

    if(Found == False): #in None Device Found
		CurrentCombo = NewCombo
        win.deviceCombo.remove_all()
        win.StatusLab.set_text(_("No Device Found"))
        win.deviceCombo.set_active(0)
        win.GeneralBox.set_sensitive(0)
        #Clear Globalvars
		del(GLOBAL);del(config);GLOBAL = None;config = None
		
    else:#If Device Found
		win.deviceCombo.remove_all()
        CurrentCombo = NewCombo

        #Make Combobox
        for DevName in NewCombo:
			win.deviceCombo.prepend_text(NewCombo[DevName])

        #Check already Selected Device
        if(win.deviceCombo.get_active() >= 0):
            SelectDev = win.deviceCombo.get_active()
        else:
            SelectDev = 0

        win.deviceCombo.set_active(SelectDev)
        win.toolb.set_sensitive(1)
        win.toolb2.set_sensitive(1)
        win.GeneralBox.set_sensitive(1)

		##Clear config
		del(config)
		config = {}
		
		
        CountDev = len(GLOBAL) - 1
        for i in GLOBAL:
            CurrentIndex = CountDev - i
            config[CurrentIndex] = GLOBAL[i]
		ConnectCurrentDevice(win)
	FinishtLoad = True

def CheckDevice(deviceID):
    import os
    from android_keyboard_lib.xlikan_lib import log; logger = log()

    Check = os.popen('adb -s '+deviceID+' shell "echo i_am_alive"').read()
    Check = Check.split()
    try:
        if(Check[0] != 'i_am_alive'):
            logger.debug(_('Devices')+' :'+deviceID+" "+_('Connection Problem'))
            return False
    except IndexError:
            logger.warning(_('Devices')+' :'+deviceID+" "+_('Connection Problem'))
            return False

    return True

def CheckDeviceComboChanges(NewList):
	
	from android_keyboard_lib.xlikan_lib import log; logger = log()

	logger.debug(_("Check Device Changes ..."))

	#Check New Start
	try:
		if(CurrentCombo[999] == True):
			logger.debug(_("Found Changes"))
			return True
	except KeyError:
		DuNothing = True
		
		
	if(len(NewList) != len(CurrentCombo)):
		logger.debug(_("Found Changes"))
		return True #Return Found Changes
	
	for DeviceName in NewList:
		if(NewList[DeviceName] != CurrentCombo[DeviceName]):
			logger.debug(_("Found Changes"))
			return True
			
	logger.debug(_("No Changes Found"))
	return False

def getDeviceModel(deviceID):
	import os
	from android_keyboard_lib.xlikan_lib import log; logger = log()
	deviceModel = os.popen('adb -s '+deviceID+' shell "cat /system/build.prop" | grep ro.product.model').read()

	deviceModel = deviceModel.replace('\n', '') #Filter
	deviceModel = deviceModel.split('=')
	#MODEL
	deviceModel = deviceModel[1].replace('\r','')

	return deviceModel

def GetDeviceList():
    return None

def SetLoading(win):
    from android_keyboard_lib.xlikan_lib import log; logger = log()

    logger.debug(_("Setup Form -Loading-"))
    win.StatusLab.set_text(_("Please Wait")+" ...")

    win.toolb.set_sensitive(0)
    win.toolb2.set_sensitive(0)
    win.GeneralBox.set_sensitive(0)

def ConnectCurrentDevice(win):
    import os
	
	global StatusChanges
	
	if(config == None):return #Return In No Config
	if(win.deviceCombo.get_active() == -1):return #Return In No Config
    SelectedDevice = config[win.deviceCombo.get_active()]


    #Check ADB Connection
    if(CheckDevice(SelectedDevice[0]) == False):
        win.StatusLab.set_markup("<span color='#8A0808'>"+_("ADB Connection Problem")+"</span>")
        win.InputKey.set_sensitive(0)
        win.toolb.set_sensitive(0)
        return False

    #Check WIFIKeyboard Install Status

    Package = os.popen("adb shell 'pm list packages -f' | grep apk=com.volosyukivan").read()
    if(len(Package) < 1):
        win.StatusLab.set_markup("<span color='#8A0808'>"+_("WiFiKeyboard not Installed")+"</span>")
        win.InputKey.set_sensitive(0)
        win.toolb.set_sensitive(0)
        if(StatusChanges is True):
			os.system("adb -s "+SelectedDevice[0]+" shell 'am start -a com.google.android.finsky.NAVIGATIONAL_SUGGESTION -d https://market.android.com/details?id=com.volosyukivan'")
        return False

    BindDevice(win)
    CheckWIFIKeyboardPack(win)

def BindDevice(win):
    import os
    
	if(config == None):return #Return In No Config
	if(win.deviceCombo.get_active() == -1):return #Return In No Config
	
    SelectedDevice = config[win.deviceCombo.get_active()]
    os.system('adb -s '+SelectedDevice[0]+' forward tcp:7777 tcp:7777')

def CheckWIFIKeyboardPack(win):
    import os
    from android_keyboard_lib.xlikan_lib import log,ConnecitonCheck; logger = log()
	
	if(config == None):return #Return In No Config
	if(win.deviceCombo.get_active() == -1):return #Return In No Config
	
    global CurrentGO
    global LastDeviceStatus
	global StatusChanges

    SelectedDevice = config[win.deviceCombo.get_active()]

    if(ConnecitonCheck('localhost','7777') == False):
        win.StatusLab.set_markup("<span color='#8A0808'>"+_("WIFI Keyboard Service not Found")+"</span><span size='8000'>\n"+_("Select WiFiKeyboard service as InputMethod")+"</span>")
        if(StatusChanges is True):
			os.system("adb -s "+SelectedDevice[0]+" shell 'am start -a android.intent.action.MAIN -n com.android.settings/.LanguageSettings' > /dev/null 2>&1 &")
		
		LastDeviceStatus = False
        win.InputKey.set_sensitive(0)
        win.toolb.set_sensitive(0)
        CurrentGO[0] = False
    elif(WIFIKeyboardConnecting(win) == False):
		LastDeviceStatus = False
		win.InputKey.set_sensitive(0)
        win.toolb.set_sensitive(0)
        CurrentGO[0] = False
    else:
        win.StatusLab.set_markup("<span color='#0B610B'>"+_("WIFI Keyboard Service Connected")+"</span>")

        if(LastDeviceStatus != True):
			win.toolb.set_sensitive(1)
		win.InputKey.set_sensitive(1)
			
        LastDeviceStatus = True

        CurrentGO[0] = True

def WIFIKeyboardConnecting(win):

    from urllib3 import HTTPConnectionPool

    from android_keyboard_lib.xlikan_lib import ConnecitonCheck

    global httpServ
    global seqConfirmed
    global LastDeviceStatus

    if(ConnecitonCheck("localhost", 7777) == False):
        win.StatusLab.set_markup("<span color='#8A0808'>"+_("Connection Problem")+"</span>")
        LastDeviceStatus = False
        return False
    else:
        win.StatusLab.set_markup("<span color='#0B610B'>"+_("WIFI Keyboard Service Connected")+"</span>")


    headers = {"Connection": "keep-alive"}
    httpServ = HTTPConnectionPool('localhost:7777', maxsize=1)
    r = httpServ.request('GET', '/',headers=headers)

    HTMLCode = r.data

    Found = HTMLCode[1711:1741]
    Found = Found.split("\n")
    Found = Found[0].replace("seqConfirmed =","")
    ConfiremedCode = Found.replace(";","")
    ConfiremedCode = ConfiremedCode.split()

    seqConfirmed = ConfiremedCode[0]

def ExecuteButton(event, Press, win):
    try:
        ChaCode = ord(chr(event.keyval).encode('utf-8'))
        SendKey(ChaCode, Press, win, True)
        return
    except TypeError:SendCode = ConvertKey(event.keyval, win)
    except UnicodeDecodeError:SendCode = ConvertKey(event.keyval, win)
    except ValueError:SendCode = ConvertKey(event.keyval, win)


    if(SendCode != None):
        SendKey(SendCode, Press, win, False)
    return

def ConvertKey(Key, win):

    Converter  = {
    65288:8, #Del
    65362:38,65364:40,65361:37,65363:39,#up,down,left,right
    65289:9, #Tab
    65293:13, #Enter
    65505:16, #Shift_left
    65307:27, #Back
    65470:113, #Menu
    65451:121,65453:120, #VolUp,VolDown
    }

    try:
        return Converter[Key]
    except KeyError:
        return None

def ReloadButtonSupport(Key):

    Support = {

    }

    try:
        return Support[Key]
    except KeyError:
        return Key

def SendKey(Code, Press, win, Char):

    from urllib3 import HTTPConnectionPool
    from android_keyboard_lib.xlikan_lib import log,ConnecitonCheck; logger = log()


    global seqConfirmed
    global httpServ
    global PressedKeys

    seqConfirmed = int(seqConfirmed) + 1
    extra = ''
    #Check Connection
    if(ConnecitonCheck("localhost", 7777) == False):
        ConnectCurrentDevice(win)
        win.StatusLab.set_markup("<span color='#8A0808'>"+_("Connection Problem")+"</span>")
        return False
    else:
        win.StatusLab.set_markup("<span color='#0B610B'>"+_("WIFI Keyboard Service Connected")+"</span>")


    if(Char):
        Job = 'C'
        PressedKeys = 'C'
    elif(Press):
        Job = 'D'
        PressedKeys = Code
    else:
        Job = 'U'
        PressedKeys = None

    headers = {"Connection": "keep-alive"}
    r = httpServ.request('GET', "/key?"+str(seqConfirmed)+","+Job+str(Code)+","+extra ,headers=headers)
    result = r.data

    if(result == 'ok'):
        logger.debug(_("Send")+" : KeyCode :"+Job+str(Code))
    elif(result == 'multi'):
        logger.warning(_("Multi Connection not Excepted"))
    return True



		
	
